import { Byte } from '../../api/io/Byte';
import { BattleFightParam } from './BattleFightParam';
import { ITimer } from '../../api/timer/ITimer';
import { IAsync } from '../../api/event/IAsync';



/**战报-数值变更属性枚举*/
export const enum E_BriNumberUpdate {
	/**角色id*/
	ACTOR_ID = 0,
	/**属性类型*/
	ATTR_TYPE = 1,
	/**数值类型*/
	NUM_TYPE = 2,
	/**当前值*/
	CURV = 3,
	/**最大值*/
	MAXV = 4,
	/**变化值*/
	UPDATEV = 5,
	/**真实变化值*/
	TRUE_UPDATEV = 6,
	/**来源类型*/
	FROM_TYPE = 7,
	/**参数*/
	PARAM = 8,
	/**枚举数量*/
	EnumCount = 9
}


/**战报-数值变更*/
export class BriNumberUpdate {
	/**事件ID*/
	public static readonly EVENT_ID = 'STRUCT_DATA_BRI_NUMBER_UPDATE_EVENT_ID';
	/**整体更新事件ID（部分只需要监听整体变化）*/
	public static readonly TOTAL_EVENT_ID = 'STRUCT_DATA_BRI_NUMBER_UPDATE_TOTAL_EVENT_ID';
	/**缓存池*/
	private static POOL: BriNumberUpdate[] = [];

	/**创建入口*/
	public static create(json?: string): BriNumberUpdate {
		const c = this.POOL.pop() || new BriNumberUpdate();
		c._destroyed = false;
		c.resetProperty();
		if (json) {
			c.parse(json);
		}
		return c;
	}


	/**已释放*/
	protected _destroyed = false;
	/**角色id (uint16)*/
	protected _actorId: number;
	/**属性类型 (uint8)*/
	protected _attrType: number;
	/**数值类型 (uint16)*/
	protected _numType: number;
	/**当前值 (long)*/
	protected _curv: number;
	/**最大值 (long)*/
	protected _maxv: number;
	/**变化值 (long)*/
	protected _updatev: number;
	/**真实变化值 (long)*/
	protected _trueUpdatev: number;
	/**来源类型 (int8)*/
	protected _fromType: number;
	/**参数*/
	protected _param: BattleFightParam = null;


	/**构建函数-私有，防止外部创建*/
	private constructor() {
	}


	/**释放*/
	public destroy(): void {
		if (this._destroyed) {
			return;
		}
		this._destroyed = true;
		this.resetProperty(true);
		if (BriNumberUpdate.POOL.indexOf(this) === -1) {
			BriNumberUpdate.POOL.push(this);
		}
	}

	/**角色id*/
	public get actorId() {
		return this._actorId;
	}


	/**角色id*/
	public set actorId(v: number) {
		this._actorId = v;
	}


	/**属性类型*/
	public get attrType() {
		return this._attrType;
	}


	/**属性类型*/
	public set attrType(v: number) {
		this._attrType = v;
	}


	/**数值类型*/
	public get numType() {
		return this._numType;
	}


	/**数值类型*/
	public set numType(v: number) {
		this._numType = v;
	}


	/**当前值*/
	public get curv() {
		return this._curv;
	}


	/**当前值*/
	public set curv(v: number) {
		this._curv = v;
	}


	/**最大值*/
	public get maxv() {
		return this._maxv;
	}


	/**最大值*/
	public set maxv(v: number) {
		this._maxv = v;
	}


	/**变化值*/
	public get updatev() {
		return this._updatev;
	}


	/**变化值*/
	public set updatev(v: number) {
		this._updatev = v;
	}


	/**真实变化值*/
	public get trueUpdatev() {
		return this._trueUpdatev;
	}


	/**真实变化值*/
	public set trueUpdatev(v: number) {
		this._trueUpdatev = v;
	}


	/**来源类型*/
	public get fromType() {
		return this._fromType;
	}


	/**来源类型*/
	public set fromType(v: number) {
		this._fromType = v;
	}


	/**参数*/
	public get param() {
		return this._param;
	}



	/**通过枚举获取值*/
	public getV(k: E_BriNumberUpdate): any {
		switch (k) {
			case E_BriNumberUpdate.ACTOR_ID: return this._actorId;
			case E_BriNumberUpdate.ATTR_TYPE: return this._attrType;
			case E_BriNumberUpdate.NUM_TYPE: return this._numType;
			case E_BriNumberUpdate.CURV: return this._curv;
			case E_BriNumberUpdate.MAXV: return this._maxv;
			case E_BriNumberUpdate.UPDATEV: return this._updatev;
			case E_BriNumberUpdate.TRUE_UPDATEV: return this._trueUpdatev;
			case E_BriNumberUpdate.FROM_TYPE: return this._fromType;
			case E_BriNumberUpdate.PARAM: return this._param;
			default: return null;
		}
	}


	/**通过枚举设置值*/
	public setV(k: E_BriNumberUpdate, v: any): void {
		switch (k) {
			case E_BriNumberUpdate.ACTOR_ID: this._actorId = v; break;
			case E_BriNumberUpdate.ATTR_TYPE: this._attrType = v; break;
			case E_BriNumberUpdate.NUM_TYPE: this._numType = v; break;
			case E_BriNumberUpdate.CURV: this._curv = v; break;
			case E_BriNumberUpdate.MAXV: this._maxv = v; break;
			case E_BriNumberUpdate.UPDATEV: this._updatev = v; break;
			case E_BriNumberUpdate.TRUE_UPDATEV: this._trueUpdatev = v; break;
			case E_BriNumberUpdate.FROM_TYPE: this._fromType = v; break;
			case E_BriNumberUpdate.PARAM: this._param = v; break;
			default: break;
		}
	}


	/**初始化*/
	public resetProperty(fromDestroy = false): void {
		//角色id
		this._actorId = 0;
		//属性类型
		this._attrType = 0;
		//数值类型
		this._numType = 0;
		//当前值
		this._curv = 0;
		//最大值
		this._maxv = 0;
		//变化值
		this._updatev = 0;
		//真实变化值
		this._trueUpdatev = 0;
		//来源类型
		this._fromType = 0;
		//参数
		if (this._param) {
			this._param.destroy();
			this._param = null;
		}
		if (!fromDestroy) {
			this._param = BattleFightParam.create();
		}
	}


	/**序列化*/
	public stringify(toString: boolean): string | any {
		const json: any = {};
		if (this._actorId) {
			json.actorId = this._actorId;
		}
		if (this._attrType) {
			json.attrType = this._attrType;
		}
		if (this._numType) {
			json.numType = this._numType;
		}
		if (this._curv) {
			json.curv = this._curv;
		}
		if (this._maxv) {
			json.maxv = this._maxv;
		}
		if (this._updatev) {
			json.updatev = this._updatev;
		}
		if (this._trueUpdatev) {
			json.trueUpdatev = this._trueUpdatev;
		}
		if (this._fromType) {
			json.fromType = this._fromType;
		}
		if (this._param) {
			json.param = this._param.stringify(false);
		}

		return toString ? JSON.stringify(json) : json;
	}


	/**反序列化*/
	public parse(jsonv: string | any): this {
		this.resetProperty();
		if (!jsonv) {
			return this;
		}
		const json = typeof (jsonv) === 'string' ? JSON.parse(jsonv) : jsonv;
		if (json.actorId) {
			this._actorId = json.actorId;
		}
		if (json.attrType) {
			this._attrType = json.attrType;
		}
		if (json.numType) {
			this._numType = json.numType;
		}
		if (json.curv) {
			this._curv = json.curv;
		}
		if (json.maxv) {
			this._maxv = json.maxv;
		}
		if (json.updatev) {
			this._updatev = json.updatev;
		}
		if (json.trueUpdatev) {
			this._trueUpdatev = json.trueUpdatev;
		}
		if (json.fromType) {
			this._fromType = json.fromType;
		}
		if (json.param) {
			this._param.destroy();
			this._param = BattleFightParam.create(json.param);
		}
		return this;
	}


	/**序列化-二进制*/
	public toBytes(byte: Byte): void {
		if (!byte) {
			return;
		}
		byte.writeUint16(this._actorId);
		byte.writeUint8(this._attrType);
		byte.writeUint16(this._numType);
		byte.writeLongNumber(this._curv);
		byte.writeLongNumber(this._maxv);
		byte.writeLongNumber(this._updatev);
		byte.writeLongNumber(this._trueUpdatev);
		byte.writeInt8(this._fromType);
		this._param.toBytes(byte);
	}


	/**反序列化-二进制*/
	public fromBytes(byte: Byte): this {
		this.resetProperty();
		if (!byte) {
			return;
		}
		this._actorId = byte.readUint16();
		this._attrType = byte.readUint8();
		this._numType = byte.readUint16();
		this._curv = byte.readLongNumber();
		this._maxv = byte.readLongNumber();
		this._updatev = byte.readLongNumber();
		this._trueUpdatev = byte.readLongNumber();
		this._fromType = byte.readInt8();
		this._param.fromBytes(byte);
		return this;
	}


	/**克隆*/
	public clone(): BriNumberUpdate {
		const byte = Byte.createFromPool();
		this.toBytes(byte);
		byte.pos = 0;
		const clonev = BriNumberUpdate.create().fromBytes(byte);
		Byte.recoverToPool(byte);
		return clonev;
	}


	/**处理更新*/
	public processUpdate(jsonv: string): void {
		if (!jsonv) {
			return;
		}

		const eventID = BriNumberUpdate.EVENT_ID;
		const us = JSON.parse(jsonv);

		for (let i = 0, len = us.length; i < len;) {
			const idx = us[i];
			//角色id
			if (idx === E_BriNumberUpdate.ACTOR_ID) {
				const oldv = this._actorId;
				this._actorId = us[i + 1];
				IAsync.dispatch(eventID, idx, this._actorId, oldv);
				i += 2;
				continue;
			}
			//属性类型
			if (idx === E_BriNumberUpdate.ATTR_TYPE) {
				const oldv = this._attrType;
				this._attrType = us[i + 1];
				IAsync.dispatch(eventID, idx, this._attrType, oldv);
				i += 2;
				continue;
			}
			//数值类型
			if (idx === E_BriNumberUpdate.NUM_TYPE) {
				const oldv = this._numType;
				this._numType = us[i + 1];
				IAsync.dispatch(eventID, idx, this._numType, oldv);
				i += 2;
				continue;
			}
			//当前值
			if (idx === E_BriNumberUpdate.CURV) {
				const oldv = this._curv;
				this._curv = us[i + 1];
				IAsync.dispatch(eventID, idx, this._curv, oldv);
				i += 2;
				continue;
			}
			//最大值
			if (idx === E_BriNumberUpdate.MAXV) {
				const oldv = this._maxv;
				this._maxv = us[i + 1];
				IAsync.dispatch(eventID, idx, this._maxv, oldv);
				i += 2;
				continue;
			}
			//变化值
			if (idx === E_BriNumberUpdate.UPDATEV) {
				const oldv = this._updatev;
				this._updatev = us[i + 1];
				IAsync.dispatch(eventID, idx, this._updatev, oldv);
				i += 2;
				continue;
			}
			//真实变化值
			if (idx === E_BriNumberUpdate.TRUE_UPDATEV) {
				const oldv = this._trueUpdatev;
				this._trueUpdatev = us[i + 1];
				IAsync.dispatch(eventID, idx, this._trueUpdatev, oldv);
				i += 2;
				continue;
			}
			//来源类型
			if (idx === E_BriNumberUpdate.FROM_TYPE) {
				const oldv = this._fromType;
				this._fromType = us[i + 1];
				IAsync.dispatch(eventID, idx, this._fromType, oldv);
				i += 2;
				continue;
			}
			//参数
			if (idx === E_BriNumberUpdate.PARAM) {
				const fui: string = us[i + 1];
				if (this._param) {
					this._param.processUpdate(fui);
				}
				else {
					console.error('BriNumberUpdate param is null when update.');
				}
				IAsync.dispatch(eventID, idx);
				i += 2;
				continue;
			}

			console.error('[Struct Data] can not find enum in BriNumberUpdate with idx = ' + idx + ', version maybe wrong.')
		}

		//全更事件
		ITimer.callLater(this, this.dispatchTotalUpdate);
	}


	/**比对不一致结果*/
	public getCompareInfo(other: BriNumberUpdate): string {
		if (!other) {
			return null;
		}

		const updates: any[] = [];

		if (this._actorId !== other._actorId) {
			updates.push(E_BriNumberUpdate.ACTOR_ID, this._actorId);
		}
		if (this._attrType !== other._attrType) {
			updates.push(E_BriNumberUpdate.ATTR_TYPE, this._attrType);
		}
		if (this._numType !== other._numType) {
			updates.push(E_BriNumberUpdate.NUM_TYPE, this._numType);
		}
		if (this._curv !== other._curv) {
			updates.push(E_BriNumberUpdate.CURV, this._curv);
		}
		if (this._maxv !== other._maxv) {
			updates.push(E_BriNumberUpdate.MAXV, this._maxv);
		}
		if (this._updatev !== other._updatev) {
			updates.push(E_BriNumberUpdate.UPDATEV, this._updatev);
		}
		if (this._trueUpdatev !== other._trueUpdatev) {
			updates.push(E_BriNumberUpdate.TRUE_UPDATEV, this._trueUpdatev);
		}
		if (this._fromType !== other._fromType) {
			updates.push(E_BriNumberUpdate.FROM_TYPE, this._fromType);
		}
		//参数
		{
			const ui = this._param.getCompareInfo(other._param);
			if (ui && ui.length > 0) {
				updates.push(E_BriNumberUpdate.PARAM, ui);
			}
		}

		const jsonv = updates.length === 0 ? null : JSON.stringify(updates);
		return jsonv;
	}


	/**全部更新*/
	protected dispatchTotalUpdate(): void {
		IAsync.dispatch(BriNumberUpdate.TOTAL_EVENT_ID, this.getV(0));
	}

}
